/*===============================================
*   文件名称：tcp_server.c
*   创 建 者：     
*   创建日期：2024年09月19日
*   描    述：
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>

//初始化
int tcp_server_init(const char *ip, int port, int backlog);
//等待连接
int tcp_server_wait(int listenfd);
//子进程处理客户端请求的执行函数:处理对应客户端的连接请求
void client_handler(int nfd);

void child_handler(int no)
{
    if(no == SIGCHLD){
        wait(NULL);
    }else if(no == SIGINT){
        kill(0, SIGKILL);
    }
}

int main(int argc, char *argv[])
{ 
    signal(SIGCHLD, child_handler);
    signal(SIGINT, child_handler);
    int listenfd = tcp_server_init("0", 8888, 50);
    if(-1 == listenfd){
        perror("init");
        return -1;
    }

    while(1){
        int nfd = tcp_server_wait(listenfd);
        if(-1 == nfd){
            perror("wait");
            continue;
        }
        //创建子进程处理对应的请求
        pid_t pid = fork();
        if(-1 == pid){
            perror("fork");
            continue;
        }else if(pid > 0){
            close(nfd); //父进程只是等待客户端连接而不会处理对应请求,所以关闭
        }else{
            close(listenfd);  //子进程用不到监听套接字所以关闭节约资源
            client_handler(nfd);
            exit(0);
        }
    }
    return 0;
} 
//初始化
int tcp_server_init(const char *ip, int port, int backlog)
{
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == fd)
        return fd;
    struct sockaddr_in saddr;
    saddr.sin_family      = AF_INET;
    saddr.sin_port        = htons(port);
    saddr.sin_addr.s_addr = inet_addr(ip);

    if(-1 == bind(fd, (void *)&saddr, sizeof saddr))
        return -1;

    if(-1 == listen(fd, backlog))
        return -1;
    puts("listen...");
    return fd;
}
//等待连接
int tcp_server_wait(int listenfd)
{
    struct sockaddr_in caddr; //用来存储连接的客户端的IP PORT
    socklen_t len = sizeof caddr;

    int nfd = accept(listenfd, (void *)&caddr, &len);
    if(-1 == nfd)
        return -1;
    printf("Client %s:%d connected!\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
    return nfd;
}
//线程的执行函数:处理对应客户端的连接请求
void client_handler(int nfd)
{
    char buf[128];
    while(1){
        if(0 >= read(nfd, buf, 128)){
            break;
        }
        if(0 == strncasecmp(buf, "time?", 5)){
            time_t tm = time(NULL);
            sprintf(buf, "Now Time:%s", ctime(&tm));
        }else{
            sprintf(buf, "你可以这样问我:time?\n");
        }
        write(nfd, buf, 128);
    }
    close(nfd);
}
